<?php

namespace PSC\Loader;

/**
 * Autocarregamento de Classes
 *
 * Estrutura básica para criação de um autocarregador de classes que utiliza uma
 * camada de mapeamento para encontrar os arquivos necessários para inclusão.
 * Conforme o sufixo da estrutura solicitada, seja ela classe ou interface, é
 * possível a utilização do mapa a partir do primeiro elemento de nomenclatura
 * da classe. Utiliza o padrão de projeto Singleton para inicializar uma
 * instância única da classe na memória e acesso centralizado.
 *
 * @category PSC
 * @package  PSC\Loader
 */
class Autoloader
{
    /**
     * Instância Singleton
     * @var Autoloader
     */
    private static $_instance = null;

    /**
     * Mapeamento para Caminhos de Inclusão
     * @var array
     */
    protected $_mapper = array();

    /**
     * Acesso Singleton
     *
     * Método utilizado para acessar a instância única Singleton, baseado no
     * padrão de projeto homônimo. Verifica se o objeto já foi criado, caso
     * contrário cria uma nova instância, configurando-a como autocarregador.
     *
     * @return Autoloader Instância Singleton Solicitada
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * Construtor Singleton
     *
     * Construtor privado para inibir a construção de outra instância da classe,
     * seguindo o padrão de projeto Singleton. Inicializa o autocarregador de
     * classes dentro da execução na linguagem.
     */
    private function __construct()
    {
        // Inicializar Autocarregamento
        spl_autoload_register(array($this, 'load'));
    }

    /**
     * Configuração de Prefixo para Mapeamento
     *
     * Durante a execução do programa, a estrutura de autocarregamento de
     * classes e interfaces utiliza um método especial para buscar os arquivos
     * necessários na camada de mapeamento, configurada por este método.
     *
     * @param  $prefix    Prefixo da Classe para Consulta
     * @param  $filepath  Caminho Base para Consulta do Arquivo
     * @return Autoloader Próprio Objeto para Encadeamento
     */
    public function setMapper($prefix, $filepath)
    {
        // Conversão
        $prefix   = (string) $prefix;
        $filepath = (string) $filepath;
        // Configuração
        $this->_mapper[$prefix] = $filepath;
        // Encadeamento
        return $this;
    }

    /**
     * Carregamento de Elementos
     *
     * Durante a execução do código do programa, sempre que uma classe ou
     * interface não foi ainda carregada no sistema, o PHP utiliza os
     * autocarregadores para procurar os recursos necessários. Estes recebem
     * como parâmetro o nome da estrutura e podem efetuar uma pesquisa com base
     * nestas informações. O primeiro sufixo utilizado deve estar registrado no
     * mapeamento do autocarregador, caso contrário a estrutura solicitada será
     * ignorada.
     *
     * @param  string $element Nome da Classe ou Interface para Carregamento
     * @return bool   Resultado Final da Ação Solicitada
     */
    public function load($element)
    {
        // Resultado Inicial
        $result  = false;
        // Conversão
        $element = (string) $element;
        // Captura de Tokens
        $content = explode('\\', $element);
        // Captura de Prefixo
        $prefix  = array_shift($content);
        // Verificação do Mapeamento
        if (array_key_exists($prefix, $this->_mapper)) {
            // Caminho do Arquivo
            $filepath = $this->_mapper[$prefix];
            // Construção de Caminho do Arquivo
            $filename = implode(DIRECTORY_SEPARATOR,
                array_merge(array($filepath), $content)) . '.php';
            // Captura de Arquivo
            require_once $filename;
            // Resultado de Mapeamento
            $return = true;
        }
        // Retorno
        return $result;
    }
}

